/*
 * SpriteLoader.cpp
 *
 *  Created on: 2009/01/29
 *      Author: Yongshik Cho
 */

#include "SpriteLoader.h"
#include "SoundReader.h"
#include "CollisionReader.h"
#include "TileReader.h"
#include "TweenReader.h"
#include "PathReader.h"
#include "TextReader.h"
#include "ParticleReader.h"
#include "../ScriptManager.h"
#include "../SceneManager.h"
#include "../core/Rect2D.h"
#include "sqplus/sqplus.h"

using namespace SqPlus;

const std::string SpriteLoader::_SPRITE_TAG 	= "Sprite";
const std::string SpriteLoader::_TILE_TAG		= "Tile";
const std::string SpriteLoader::_SOUND_TAG		= "Sound";
const std::string SpriteLoader::_PATH_TAG		= "Path";
const std::string SpriteLoader::_TEXT_OBJECT_TAG	= "TextObject";
const std::string SpriteLoader::_PARTICLE_TAG		= "Particle";


Sprite* SpriteLoader::parse(const String& path)
{
#ifdef UNICODE
	char mbstr[512]; memset(mbstr, 0, 512);
	::WideCharToMultiByte(CP_UTF8, 0, path.c_str(), (int32)path.size(), mbstr, 512, 0, 0);
	TiXmlDocument* doc = new TiXmlDocument(mbstr);
#else
	TiXmlDocument* doc = new TiXmlDocument(path.c_str());
#endif
	if(!doc)
		AltoThrow(Exception::ERR_MEMORY);

	if(!doc->LoadFile(TIXML_ENCODING_UTF8))
		return 0;

	return parse(doc->FirstChildElement(_SPRITE_TAG.c_str()));
}

Sprite* SpriteLoader::parse(TiXmlElement* element)
{
	Sprite* sprite = new Sprite();
	if(!sprite)
		AltoThrow(Exception::ERR_MEMORY);

	/*
	 * 	<Sound path='Bomb.ogg' Rolloff=0>
		<Volume left=1 right=1>
		<Position x=0 y=0/>
		<Velocity x=0 y=0/>
		<Direction x=0 y=0/>
		<LoopType type=LOOP_COUNT/>
		<LoopCount count=1/>
		</Sound>
	 *
	 */
	char *sCenterType, *sFlipType, *sCollideType, *sLocked, *sVisible, *sBlendColor, *sVisibleRect, *sVisibleCenter;

	sCenterType = (char*)element->Attribute(TileReader::_CENTERTYPE_TAG.c_str());
	sFlipType = (char*)element->Attribute(TileReader::_FLIPTYPE_TAG.c_str());
	sCollideType = (char*)element->Attribute(TileReader::_COLLIDETYPE_TAG.c_str());
	sBlendColor = (char*)element->Attribute(TileReader::_BLENDCOLOR_TAG.c_str());
	sLocked = (char*)element->Attribute(TileReader::_LOCKED_TAG.c_str());
	sVisibleRect = (char*)element->Attribute(TileReader::_VISIBLE_RECT_TAG.c_str());
	sVisibleCenter = (char*)element->Attribute(TileReader::_VISIBLE_CENTER_TAG.c_str());
	sVisible = (char*)element->Attribute(TileReader::_VISIBLE_TAG.c_str());
	char* sBlendType = (char*)element->Attribute(TileReader::_BLENDTYPE_TAG.c_str());
	char* sSort = (char*)element->Attribute(TileReader::_SORT_TAG.c_str());

	TiXmlElement* node = element->FirstChildElement(TileReader::_CENTERTYPE_TAG.c_str()); if(node) sCenterType = (char*)node->GetText();
	node = element->FirstChildElement(TileReader::_FLIPTYPE_TAG.c_str()); if(node) sFlipType = (char*)node->GetText();
	node = element->FirstChildElement(TileReader::_COLLIDETYPE_TAG.c_str()); if(node) sCollideType = (char*)node->GetText();
	node = element->FirstChildElement(TileReader::_BLENDCOLOR_TAG.c_str()); if(node) sBlendColor = (char*)node->GetText();
	node = element->FirstChildElement(TileReader::_LOCKED_TAG.c_str()); if(node) sLocked = (char*)node->GetText();
	node = element->FirstChildElement(TileReader::_VISIBLE_RECT_TAG.c_str()); if(node) sVisibleRect = (char*)node->GetText();
	node = element->FirstChildElement(TileReader::_VISIBLE_CENTER_TAG.c_str()); if(node) sVisibleCenter = (char*)node->GetText();
	node = element->FirstChildElement(TileReader::_VISIBLE_TAG.c_str()); if(node) sVisible = (char*)node->GetText();
	node = element->FirstChildElement(TileReader::_BLENDTYPE_TAG.c_str()); if(node) sBlendType = (char*)node->GetText();
	node = element->FirstChildElement(TileReader::_SORT_TAG.c_str()); if(node) sSort = (char*)node->GetText();

	char* sName = (char*)element->Attribute(TileReader::_NAME_TAG.c_str());
	node = element->FirstChildElement(TileReader::_NAME_TAG.c_str()); if(node) sName = (char*)node->GetText();

	if(sName)
#ifdef UNICODE
	{
		TCHAR wstr[512]; memset(wstr, 0, sizeof(wstr));
		::MultiByteToWideChar(CP_UTF8, 0, sName, (int32)strlen(sName), wstr, 512);
		sprite->setName(wstr);
	}
#else
		sprite->setName(sName);
#endif

	if(sCenterType)
	{
		if(sCenterType == TileReader::_CENTER_LT_TAG)
			sprite->setCenterType(Rect2D::CENTER_LT);
		else if(sCenterType == TileReader::_CENTER_CT_TAG)
			sprite->setCenterType(Rect2D::CENTER_CT);
		else if(sCenterType == TileReader::_CENTER_RT_TAG)
			sprite->setCenterType(Rect2D::CENTER_RT);
		else if(sCenterType == TileReader::_CENTER_LM_TAG)
			sprite->setCenterType(Rect2D::CENTER_LM);
		else if(sCenterType == TileReader::_CENTER_CM_TAG)
			sprite->setCenterType(Rect2D::CENTER_CM);
		else if(sCenterType == TileReader::_CENTER_RM_TAG)
			sprite->setCenterType(Rect2D::CENTER_RM);
		else if(sCenterType == TileReader::_CENTER_LB_TAG)
			sprite->setCenterType(Rect2D::CENTER_LB);
		else if(sCenterType == TileReader::_CENTER_CB_TAG)
			sprite->setCenterType(Rect2D::CENTER_CB);
		else if(sCenterType == TileReader::_CENTER_RB_TAG)
			sprite->setCenterType(Rect2D::CENTER_RB);
	}

	if(sFlipType)
	{
		if(sFlipType == TileReader::_FLIP_NONE_TAG)
			sprite->setFlipType(Renderable::FLIP_NONE);
		else if(sFlipType == TileReader::_FLIP_LEFTRIGHT_TAG)
			sprite->setFlipType(Renderable::FLIP_LEFT_RIGHT);
		else if(sFlipType == TileReader::_FLIP_TOPBOTTOM_TAG)
			sprite->setFlipType(Renderable::FLIP_TOP_BOTTOM);
	}

	if(sCollideType)
	{
		if(sCollideType == TileReader::_COLLIDABLE_PIXEL_TAG)
			sprite->setCollideType(Collidable::COLLIDABLE_PIXEL);
		else if(sCollideType == TileReader::_COLLIDABLE_LINE_TAG)
			sprite->setCollideType(Collidable::COLLIDABLE_LINE);
		else if(sCollideType == TileReader::_COLLIDABLE_TRIANGLE_TAG)
			sprite->setCollideType(Collidable::COLLIDABLE_TRIANGLE);
		else if(sCollideType == TileReader::_COLLIDABLE_RECT_TAG)
			sprite->setCollideType(Collidable::COLLIDABLE_RECT);
		else if(sCollideType == TileReader::_COLLIDABLE_POLYGON_TAG)
			sprite->setCollideType(Collidable::COLLIDABLE_POLYGON);
	}

	if(sBlendColor)
	{
		uint32 blendColor;
		Color color;

		sscanf(sBlendColor, "%x", &blendColor);
		color = Color::fromARGB((float)((blendColor>>24)&0xFF)/255.f, (float)((blendColor>>16)&0xFF)/255.f,
				(float)((blendColor>>8)&0xFF)/255.f, (float)((blendColor>>0)&0xFF)/255.f);
		sprite->setBlendColor(color);
	}

	if(sLocked)
	{
		if(sLocked == TileReader::_TRUE_TAG)
			sprite->setLocked(true);
		else if(sLocked == TileReader::_FALSE_TAG)
			sprite->setLocked(false);
	}

	if(sVisibleRect)
	{
		if(sVisibleRect == TileReader::_TRUE_TAG)
			sprite->setVisibleRect(true);
		else if(sVisibleRect == TileReader::_FALSE_TAG)
			sprite->setVisibleRect(false);
	}

	if(sVisibleCenter)
	{
		if(sVisibleCenter == TileReader::_TRUE_TAG)
			sprite->setVisibleCenter(true);
		else if(sVisibleCenter == TileReader::_FALSE_TAG)
			sprite->setVisibleCenter(false);
	}

	if(sVisible)
	{
		if(sVisible == TileReader::_TRUE_TAG)
			sprite->setVisible(true);
		else if(sVisible == TileReader::_FALSE_TAG)
			sprite->setVisible(false);
	}

	if(sSort)
	{
		if(sSort == TileReader::_TRUE_TAG)
			sprite->setSort(true);
		else if(sSort == TileReader::_FALSE_TAG)
			sprite->setSort(false);
	}

	int32 x=0, y=0;
	double sx=1.f, sy=1.f, angle=0.f;

	TiXmlElement* origin = element->FirstChildElement(TileReader::_ORIGIN_TAG.c_str());
	if(origin)
	{
		origin->Attribute(TileReader::_X_TAG.c_str(), &x);
		node = origin->FirstChildElement(TileReader::_X_TAG.c_str()); if(node) x = atoi(node->GetText());
		origin->Attribute(TileReader::_Y_TAG.c_str(), &y);
		node = origin->FirstChildElement(TileReader::_Y_TAG.c_str()); if(node) y = atoi(node->GetText());

		sprite->setOrigin(Vector2D((float)x, (float)y));
	}

	TiXmlElement* up = element->FirstChildElement(TileReader::_UP_TAG.c_str());
	if(up)
	{
		up->Attribute(TileReader::_X_TAG.c_str(), &x);
		node = up->FirstChildElement(TileReader::_X_TAG.c_str()); if(node) x = atoi(node->GetText());
		up->Attribute(TileReader::_Y_TAG.c_str(), &y);
		node = up->FirstChildElement(TileReader::_Y_TAG.c_str()); if(node) y = atoi(node->GetText());

		sprite->setUp(Vector2D((float)x, (float)y));
	}

	TiXmlElement* position = element->FirstChildElement(TileReader::_POSITION_TAG.c_str());
	if(position)
	{
		position->Attribute(TileReader::_X_TAG.c_str(), &x);
		TiXmlElement* node = position->FirstChildElement(TileReader::_X_TAG.c_str()); if(node) x = atoi(node->GetText());
		position->Attribute(TileReader::_Y_TAG.c_str(), &y);
		node = position->FirstChildElement(TileReader::_Y_TAG.c_str()); if(node) y = atoi(node->GetText());

		sprite->setPosition(Vector2D((float)x, (float)y));
	}

	TiXmlElement* rotation = element->FirstChildElement(TileReader::_ROTATION_TAG.c_str());
	if(rotation)
	{
		rotation->Attribute(TileReader::_ANGLE_TAG.c_str(), &angle);
		TiXmlElement* node = rotation->FirstChildElement(TileReader::_ANGLE_TAG.c_str()); if(node) angle = atof(node->GetText());

		sprite->setRotation((float)angle);
	}

	TiXmlElement* scale = element->FirstChildElement(TileReader::_SCALE_TAG.c_str());
	if(scale)
	{
		scale->Attribute(TileReader::_X_TAG.c_str(), &sx);
		TiXmlElement* node = scale->FirstChildElement(TileReader::_X_TAG.c_str()); if(node) sx = atof(node->GetText());
		scale->Attribute(TileReader::_Y_TAG.c_str(), &sy);
		node = scale->FirstChildElement(TileReader::_Y_TAG.c_str()); if(node) sy = atof(node->GetText());

		sprite->setScale(Vector2D((float)sx, (float)sy));
	}

	for(TiXmlElement* attach=element->FirstChildElement(TileReader::_ATTACHMENT_TAG.c_str());
	attach;attach=attach->NextSiblingElement(TileReader::_ATTACHMENT_TAG.c_str()))
	{
		TileReader::parseAttachment(attach, (Renderable*)sprite);
	}


	for(TiXmlElement* collision=element->FirstChildElement(TileReader::_COLLISION_TAG.c_str());
		collision;collision=collision->NextSiblingElement(TileReader::_COLLISION_TAG.c_str()))
	{
		Collidable* collidable = CollisionReader::parse(collision);
		if(collidable)
			sprite->addCollidable(collidable);
	}

	for(TiXmlElement* path=element->FirstChildElement(_PATH_TAG.c_str());
		path;path=path->NextSiblingElement(_PATH_TAG.c_str()))
	{
		Path* altoPath = PathReader::parse(path);
		if(altoPath)
			sprite->addPath(altoPath);
	}

	for(TiXmlElement* elem=element->FirstChildElement(_SOUND_TAG.c_str());
		elem;elem=elem->NextSiblingElement(_SOUND_TAG.c_str()))
	{
		Audible* audible = SoundReader::parse(elem);
		if(audible)
			sprite->addAudible(audible);
	}

	for(TiXmlElement* elem=element->FirstChildElement(_PARTICLE_TAG.c_str());
		elem;elem=elem->NextSiblingElement(_PARTICLE_TAG.c_str()))
	{
		ParticleObject* particle = ParticleReader::parse(elem);
		if(particle)
			sprite->addChild(particle);
	}

	/*
	 * 	<Tile path='PC_M000.png' xCount=4 yCount=9/>
	 */
	Tile* tile = 0;
	for(TiXmlElement* elem=element->FirstChildElement(_TILE_TAG.c_str());elem;elem=elem->NextSiblingElement(_TILE_TAG.c_str()))
	{
		tile = TileReader::parse(elem, sprite);
		if(tile)
		{
			sprite->addTile(tile);
		}
	}

	//read information about tween
	for(TiXmlElement* twn=element->FirstChildElement(TileReader::_TWEEN_TAG.c_str());twn;twn=twn->NextSiblingElement(TileReader::_TWEEN_TAG.c_str()))
	{
		TweenReader::parse(twn, (Renderable*)sprite);
	}

	//read information about text object
	for(TiXmlElement* txt=element->FirstChildElement(_TEXT_OBJECT_TAG.c_str());
		txt;txt=txt->NextSiblingElement(_TEXT_OBJECT_TAG.c_str()))
	{
		TextObject* text = TextReader::parse(txt);
		if(text)
			sprite->addChild(text);
	}

	if(sBlendType)
	{
		if(sBlendType == TileReader::_BLEND_NONE_TAG)
			sprite->setBlendType(Color::BLEND_NONE);
		else if(sBlendType == TileReader::_BLEND_ALPHA_TAG)
			sprite->setBlendType(Color::BLEND_ALPHA);
		else if(sBlendType == TileReader::_BLEND_ADD_TAG)
			sprite->setBlendType(Color::BLEND_ADD);
		else if(sBlendType == TileReader::_BLEND_SUB_TAG)
			sprite->setBlendType(Color::BLEND_SUB);
		else if(sBlendType == TileReader::_BLEND_DARKEN_TAG)
			sprite->setBlendType(Color::BLEND_DARKEN);
		else if(sBlendType == TileReader::_BLEND_LIGHTEN_TAG)
			sprite->setBlendType(Color::BLEND_LIGHTEN);
		else if(sBlendType == TileReader::_BLEND_MULTIPLY_TAG)
			sprite->setBlendType(Color::BLEND_MULTIPLY);
		else if(sBlendType == TileReader::_BLEND_SCREEN_TAG)
			sprite->setBlendType(Color::BLEND_SCREEN);
		else if(sBlendType == TileReader::_BLEND_DIFFERENCE_TAG)
			sprite->setBlendType(Color::BLEND_DIFFERENCE);
		else if(sBlendType == TileReader::_BLEND_INVERSE_DIFFERENCE_TAG)
			tile->setBlendType(Color::BLEND_INVERSE_DIFFERENCE);
		else if(sBlendType == TileReader::_BLEND_INVERT_TAG)
			tile->setBlendType(Color::BLEND_INVERT);
		else if(sBlendType == TileReader::_BLEND_DODGE_TAG)
			tile->setBlendType(Color::BLEND_DODGE);
	}

	//retrieves scene manager
	SceneManager& sm = SceneManager::GetInstance();

	//retrieves root object
	RenderObjectContainer* renderRoot = sm.getRenderRoot();

	renderRoot->addChild(sprite);

	//parse information about scripts
	parseScripts(element, sprite);

	return sprite;
}

void SpriteLoader::parseScripts(TiXmlElement* element, Sprite* sprite)
{
	char* scriptFile = (char*)element->Attribute(TileReader::_SCRIPT_FILE_TAG.c_str());
	TiXmlElement* node = element->FirstChildElement(TileReader::_SCRIPT_FILE_TAG.c_str()); if(node) scriptFile = (char*)node->GetText();

	if(scriptFile)
	{
#ifdef UNICODE
		TCHAR wstr[512]; memset(wstr, 0, sizeof(wstr));
		::MultiByteToWideChar(CP_UTF8, 0, scriptFile, (int32)strlen(scriptFile), wstr, 512);
		ScriptManager::GetInstance().load(wstr);
#else
		ScriptManager::GetInstance().load(scriptFile);
#endif
	}

	char* onLoad = (char*)element->Attribute(TileReader::_ON_LOAD_TAG.c_str());
	node = element->FirstChildElement(TileReader::_ON_LOAD_TAG.c_str()); if(node) onLoad = (char*)node->GetText();

	if(onLoad)
	{
		//call script function
#ifdef UNICODE
		TCHAR wstr[512]; memset(wstr, 0, sizeof(wstr));
		::MultiByteToWideChar(CP_UTF8, 0, onLoad, (int32)strlen(onLoad), wstr, 512);
		SquirrelFunction<void>((const SQChar*)wstr)(sprite);
#else
		SquirrelFunction<void>((const SQChar*)onLoad)(sprite);
#endif
	}
}

Sprite* SpriteLoader::load(const String& path)
{
	return parse(path);
}
